/**
 * 数据模型
 * by blue
 */
fangimjs.define('model/modelParse', ['event/event', 'setting/setting', 'jquery', 'sdk/flashSocket', 'sdk/pollingSocket', 'util/util', 'json2'], function (require, exports, module) {
    'use strict';
    var setting = require('setting/setting').getInstance(),
        event = require('event/event'),
        $ = require('jquery'),
        util = require('util/util'),
        JSON = require('json2');
    var vars = fangimjs.data.vars;
    var config = vars.config;
    var localStorage = vars.localStorage;
    var FANG_IM_MSG_DATA_LIST = 'fang_im_msg_data_list';

    // yf: 自动回复逻辑从 totalController 迁移到 modelParse
    var autoReplyTimerList = {}; //自动回复定时器ID列表
    var jiajuReplyTextList = {}; //自动回复定时器ID列表
    var defaultReplyConfig = {
        default: '亲爱的用户，客服正忙，您可以先浏览其他内容，我们会尽快回复您。'
    };

    // 收到客服回复重新计时
    if (config.type === setting.type.sfb) {
        defaultReplyConfig.custom = {
            online: '您好，这里是搜房帮在线客服，很高兴为您服务！',
            offline: '您好，现在是非工作时间，请在周一到周五 9:00-18:00 期间与客服进行在线沟通，或者您可拨打客服热线 400-630-6888 由值班客服为您服务，给您带来的不便敬请谅解！',
            noUser: '客服未收到您的回复，如有需要可再次咨询我们，祝愉快！再见',
            delay: 3 * 60 * 1000
        };
    }

    if (config.type === setting.type.zxb) {
        defaultReplyConfig.custom = {
            online: '您好，我是房天下家装顾问，很高兴为您服务！请问有什么可以帮您的？',
            offline: '亲爱的房天下用户，您有什么问题可以直接留言，并留下您方便联系的电话号码，我们的客服会在工作时间尽快与您取得联系，祝您愉快！',
            noUser: '感谢您的咨询，祝您生活愉快！热线电话：400-919-2000',
            delay: 10 * 60 * 1000
        };
    }

    /**
     * 获取联系人列表总新消息数
     */
    function getTotalMsgNumber(arr) {
        var num = 0;
        var l = arr.length;
        for (var i = 0; i < l; i++) {
            if (arr[i].newmsgnum) {
                num += +arr[i].newmsgnum;
            }
        }
        return num;
    }

    /**
     * 获取消息时间（根据毫秒数换算时间戳）
     * @param t
     * @returns {string}
     */
    function getMsgTime(date) {
        var arr = [];
        arr.push(date.getFullYear());
        arr.push('-');
        arr.push(date.getMonth() + 1);
        arr.push('-');
        arr.push(date.getDate());
        arr.push(' ');
        arr.push(date.getHours());
        arr.push(':');
        arr.push((100 + date.getMinutes() + '').substr(1));
        arr.push(':');
        arr.push((100 + date.getSeconds() + '').substr(1));
        return arr.join('');
    }

    /**
     * 比较前后两个数组内容是否相同
     * 最近联系人列表数据与socket传入的最近联系人列表数据比较
     * @param arra
     * @param arrb
     * @returns {boolean}
     */
    function sameArr(arra, arrb) {
        if (arra.length != arrb.length) {
            return false;
        } else {
            var l = arra.length;
            for (var i = 0; i < l; i++) {
                var a = arra[i];
                var b = arrb[i];
                if (a.contactId != b.uid || a.newmsgnum != b.newmsgnum || a.state != b.state) {
                    return false;
                }
            }
        }
        return true;
    }
    /**
     * 比较前后两个数据中联系人状态是否发生了变化
     * @param arra
     * @param arrb
     * @returns {boolean}
     */
    function compareContactState(arra, obj) {
        var result = false;
        var l = arra.length;
        for (var i = 0; i < l; i++) {
            var a = arra[i];
            if (undefined !== obj[a.contactId] && a.state != obj[a.contactId]) {
                a.state = obj[a.contactId];
                result = true;
            }
        }
        return result;
    }
    /**
     * 格式化联系人数据（由于来源不同极有可能出现的数据不一致的问题）
     * @param d
     * @returns {{contactId: (*|string|contactId|_vars.broker.contactId|_vars.consultant.contactId), showname: (*|showname|_vars.broker.showname|_vars.consultant.showname|_vars.config.showname|obj.showname), newmsgnum: (*|number), state: state, latesttime: *, tip: (*|tip|_vars.broker.tip|_vars.consultant.tip|textareaView.tip|string)}}
     */
    function formatContactData(d) {
        var obj = {
            contactId: d.contactId || d.uid, // 联系人Id
            showname: d.showname, // 显示名称
            newmsgnum: d.newmsgnum || 0, // 未读消息数
            state: d.state || 0, // 在线状态
            type: d.type || '', // 联系人类型 'webxf'
            latesttime: d.latesttime ? d.latesttime : '', // 登录时间
            tip: d.tip || '', // 欢迎语
            tel: d.tel || '', // 联系人电话
            shop: d.shop || '', // 店铺地址。新版本改为 loupan 字段
            avatar: d.avatar || '', // 头像
            loupan: d.loupan || '', // 新需求，添加楼盘名称
            ShopID: d.ShopID || d.shopid || '',
            ShopType: d.ShopType || d.shoptype || '',
            projinfo: d.projinfo || ''
        };
        return obj;
    }
    /**
     * 在最近联系人列表中根据唯一属性parm获取该联系人是否存在，若存在返回索引值否则返回-1
     * @param data
     * @param arr
     * @param parm
     * @returns {*}
     */
    function getArrIdx(data, arr, parm) {
        for (var i in arr) {
            var obj = arr[i];
            if (obj[parm] === data[parm]) {
                return i;
            }
        }
        return -1;
    }
    /**
     * 通过id获取当前选择的联系人数据
     * @param {Object} id 当前选择的联系人id
     * @param {Object} list 联系人数据列表
     */
    function getSelectedContact(id, list) {
        var l = list.length;
        for (var i = 0; i < l; i++) {
            var single = list[i];
            if (single.contactId == id) {
                return single;
            }
        }
        return null;
    }
    /**
     * 最近联系人列表置顶操作(将列表中一个联系人插入表头)
     * @param {Object} id
     * @param {Object} list
     */
    function insertHead(id, list) {
        var l = list.length;
        for (var i = 0; i < l; i++) {
            var single = list[i];
            if (single.contactId == id) {
                list.splice(i, 1);
                list.unshift(single);
                break;
            }
        }
    }

    /**
     * 获取最近联系人列表在线人数及总人数
     * @param {Object} data
     */
    function getOnlineAndTotalContactNum(arr) {
        var total = 0;
        var online = 0;
        var l = arr.length;
        for (var i = 0; i < l; i++) {
            if (arr[i].state == 1) {
                online++;
            }
            total++;
        }
        return {
            'online': online,
            'total': total
        };
    }

    var modelParseSingle = (function() {
        function modelParse(args) {
            this.isMaster = false; //是否为主客户端
            /**
             * selfData数据
             * city: "北京"
             regType: 0
             type: 'home'
             showname: "网友-a94f17"
             state: 2,
             sysinfotype: ""
             uid: "a94f17d1e5df00a0"
             userType: "flash"
             usercookie: ""
             */
            this.selfData = {}; //用户数据
            this.newMsgNum = 0; //新消息数量
            this.contactsOnlineStatus = {
                "online": 0,
                "total": 0
            }; //在线联系人统计
            /**
             * contactsDataList是数据其中每个元素是一个contactsData对象
             * contactsData为
             * {
             * "contactId":"f:1234567890",//联系人Id
             * "showname":"testgroupuser2",//显示
             * "newmsgnum":0,//未读消息数
             * 'shop':''， //经纪人店铺链接地址
             * 'tel':'', // 经纪人电话号码
             * 'avatar':'', // 经纪人头像地址
             * "state":0,//在线状态
             * "latesttime":""登录时间
             * }
             *
             * @type {Array}
             */
            this.contactsDataList = []; //联系人数据
            this.otherContactsDataList = {}; //其他联系人列表数据
            /**
             * msgDataList是数据其中每个元素是一个msgData对象
             * msgData为
             * {
             * "form":"f:1234567890",//来自谁
             * "sendto":"testgroupuser2",//发给谁
             * "content":"hello,testgroupuser2",//消息内容
             * "command":"chat",//为chat或img//消息类型
             * "agentname":"客户500002978",
             * "msgMine":true,//true我发的消息 false我收到的消息
             * "time":""消息时间
             * }
             *
             * msgDataList是个关联数组，其中key是contactId,value是人消息的集合，示例如下
             * msgDataList = {'jingshen':[{msgData},{msgData}], 'yuanfang':[{msgData},{msgData}]}
             * @type {Array}
             */
            this.msgDataList = {}; //聊天消息数据
            /**
             * //界面数据
             * boxstate：窗口状态有以下四种
             * -----------
             * |max |main|
             * |----|----|
             * |min |tiny|
             * -----------
             * selectedcontactid 是当前选择的联系人id
             * @type {{boxstate: string, selectedContactId: string}}
             */
            this.uiData = {
                boxState: '',
                selectedContactId: ''
            };
            /**
             * yf: 图片数据 key -> contactId : value -> picUrl
             */
            this.picData = {};
            this.PARM = 'contactId';
            this.init();
        };
        modelParse.prototype = {
            /**
             * 初始化函数
             * 注册所有数据变化监听器
             */
            init: function () {
                var that = this;
                event.on('socket:master:set', function (data) {
                    that.setMaster(data);
                });
                /*侦听来自通信层的新消息*/
                event.on('socket:msg:new', function (data) {
                    that.receiveMsg(data);
                    that.setNoUserReply('receive');
                });
                event.on('socket:msg:change', function (data) {
                    that.msgDataChange(data);
                });
                event.on('socket:ui:change', function (data) {
                    that.setBoxStateAndSelectedContactId(data.boxState, data.selectedContactId);
                });
                event.on('socket:contactlist:change', function (data) {
                    if (!sameArr(that.contactsDataList, data)) {
                        var l = data.length;
                        for (var i = 0; i < l; i++) {
                            data[i] = formatContactData(data[i]);
                        }
                        that.changeContacts(data);
                    }
                });
                event.on('socket:selfdata:set', function (data) {
                    that.selfData = data;
                });
                //保存到本地存储
                event.on('model:msg:save', function (contactId) {
                    var id = FANG_IM_MSG_DATA_LIST + contactId;
                    var msgDataHis = that.getSelectedContactHistoryMsg(contactId);
                    var msgData = that.msgDataList[contactId];
                    var exports = {};
                    if (that.mergeMsgData(msgDataHis, msgData, exports)) {
                        var str = JSON.stringify(exports.data);
                        if (localStorage) {
                            try {
                                localStorage.setItem(id, str);
                            } catch (e) {
                                localStorage.clear();
                                localStorage.setItem(id, str);
                            }
                        }
                    }
                });
            },
            /**
             * 设置通信层，分为flashsocket和长连接的方式
             * @param {Object} socketid 需要的fangimjs路径
             */
            setSocket: function (socketid) {
                var that = this;
                that.socket = require(socketid);
                that.socket.initSocket();
            },
            /** 改版二手房详情页时新增，登出并不刷新页导致重新登录并不会更新登录信息，所以添加重新初始化socket判断
             * 登录操作
             */
            login: function (init) {
                if (init) {
                    this.socket.initSocket();
                } else {
                    this.socket.login();
                }
            },
            /** 改版二手房详情页时新增，登出并不刷新页导致重新登录并不会更新登录信息，所以添加登出方法
             * 登出操作
             */
            logout: function() {
                this.socket.logout();
            },
            /**
             * 轮询状态处理
             * @param data
             */
            pollingContactsState: function (data) {
                var that = this;
                if (compareContactState(that.contactsDataList, data)) {
                    that.changeContacts(that.contactsDataList);
                    that.socket.setContactListData(that.contactsDataList);
                }
            },

            /**
             * 添加联系人
             * @param {Object} obj 增加联系人原始数据
             * @param {Object} stateObj 设置联系人在线状态数据
             */
            changeContacts: function (obj, stateObj) {
                var that = this;
                if ($.isArray(obj)) {
                    that.contactsDataList = obj;
                    that.contactsOnlineStatus = getOnlineAndTotalContactNum(that.contactsDataList);
                    event.trigger("model:contacts:change", that.contactsDataList);
                    event.trigger("model:contacts:numChange", that.contactsOnlineStatus);
                    var selectContactData = getSelectedContact(that.uiData.selectedContactId, that.contactsDataList);
                    if (selectContactData) {
                        event.trigger("model:singlecontact:change", selectContactData);
                    }
                    that.newMsgNum = getTotalMsgNumber(that.contactsDataList);
                    event.trigger('model:contact:newMsg', {
                        "contactData": selectContactData,
                        "totalMsg": that.newMsgNum
                    });
                } else {
                    var contactData = formatContactData(obj);
                    var idx = getArrIdx(contactData, that.contactsDataList, that.PARM);

                    if (idx > -1) {
		    	// 楼盘判断，loupan 字段是 2.0 版本特殊字段
                        if (contactData.loupan !== that.contactsDataList[idx].loupan
                        || contactData.showname !== that.contactsDataList[idx].showname
                        || contactData.ShopID !== that.contactsDataList[idx].ShopID
                        || contactData.ShopType !== that.contactsDataList[idx].ShopType
                        || contactData.projinfo !== that.contactsDataList[idx].projinfo
                        ) {
                            that.contactsDataList[idx] = contactData;
                            event.trigger("model:contacts:change", that.contactsDataList);
                            event.trigger('model:singlecontact:change', contactData);
                            that.socket.setContactListData(that.contactsDataList);
                        }
                        that.setBoxStateAndSelectedContactId(setting.WINDOW_STATUS_MAX, contactData.contactId, stateObj);
                        return;
                    }

                    if (stateObj) {
                        contactData.state = stateObj[contactData.contactId];
                    }
                    // yf: 如果需要最近联系人排序，需要在这里添加
                    that.contactsDataList.unshift(contactData);
                    that.socket.setContactListData(that.contactsDataList);
                    that.contactsOnlineStatus = getOnlineAndTotalContactNum(that.contactsDataList);
                    event.trigger("model:contacts:change", that.contactsDataList);
                    event.trigger("model:contacts:numChange", that.contactsOnlineStatus);
                    that.socket.addContact(contactData);

                    that.setBoxStateAndSelectedContactId(setting.WINDOW_STATUS_MAX, contactData.contactId, stateObj);

                    if (contactData.tip) {
                        that.sendMsg(contactData.tip, 1);
                    }
                }
            },

            /**
             * 改变其他联系人列表，包括“置业顾问”，“经纪人”，“客服（搜房帮、海外）”等
             * @param contacts: 页面配置的联系人，或单个联系人信息
             * @param type: 联系人类型，Consultant, Broker, CustomerService
             * @param stateMap: 联系人 contactId 对应的在线状态对象。
             * yf: 20161024 进行联系人列表在线状态排序，在线联系人提前
             */
            changeOtherContacts: function(contacts, type, stateMap) {
                var that = this;
                if ($.isArray(contacts)) {
                    var length = contacts.length,
                        onlineList = [],
                        offlineList = [];
                    for (var i = 0; i < length; i++) {
                        var contact = contacts[i];
                        var state = stateMap[contact.contactId];
                        contact.state = state;
                        if (state) {
                            onlineList.push(contact);
                        } else {
                            offlineList.push(contact);
                        }
                    }
                    that.otherContactsDataList[type] = onlineList.concat(offlineList);
                } else {
                    var contact = contacts;
                    var state = stateMap[contact.contactId];
                    contact.state = state;
                    if (state) {
                        that.otherContactsDataList[type].unshift(contact);
                    } else {
                        that.otherContactsDataList[type].push(contact);
                    }
                }
                event.trigger("model:otherContacts:change", {
                    data: that.otherContactsDataList[type],
                    type: type
                });
            },

            /**
             * 设置其他选中的联系人
             */
            setOtherSelectedContact: function (id, type, stateObj) {
                var that = this;
                var result = that.getOtherContactDataById(id, type);
                if (result) {
                    result.state = stateObj[id];
                    that.changeContacts(result, stateObj);
                }
            },

            /**
             * 其他联系人列表中通过id获取其他指定联系人
             * @param id
             * @param type
             * @returns {*}
             */
            getOtherContactDataById: function (id, type) {
                var arr = this.otherContactsDataList[type];
                var l = arr.length;
                for (var i = 0; i < l; i++) {
                    if (arr[i].contactId == id) {
                        return arr[i];
                    }
                }
                return null;
            },
            /**
             * 写入消息：将消息写入到msgDataList消息列表
             * @param msgData
             */
            writeMsg: function (msgData) {
                var that = this;
                var key = msgData.msgMine ? msgData.sendto : msgData.form;
                that.msgDataList[key] = that.msgDataList[key] || [];
                that.msgDataList[key].push(msgData);
            },
            /**
             * 写入联系人:将联系人数据写入到contactsDataList消息列表
             * @param data
             * @returns {*}
             */
            writeContactData: function (data) {
                var that = this;
                var d = formatContactData(data);
                that.contactsDataList.unshift(d);
                that.contactsOnlineStatus.online += (d.state == 1 ? 1 : 0);
                that.contactsOnlineStatus.total++;
                return d;
            },
            /**
             * 点击发送按钮时发送消息
             * @param data
             * @param autoMsg
             */
            sendMsg: function (data, autoMsg) {
                var that = this;
                if (!data) {
                    util.trace('Wrong::modelParse.sendMsg--不能发送空数据');
                    event.trigger('model:msg:alert', '发送的消息不能为空！');
                    return;
                }
                var selectedContactId = that.uiData.selectedContactId;
                if (!selectedContactId) {
                    util.trace('Wrong::modelParse.sendMsg--请选择发送对象');
                    return;
                }
                var date = new Date();

                var selectContact = getSelectedContact(that.uiData.selectedContactId, that.contactsDataList);
                var msgData = {
                    'form': that.selfData.uid, //来自谁
                    'caller': selectedContactId,
                    'sendto': selectedContactId, //发给谁
                    'content': data, //消息内容
                    'command': that.picData[selectedContactId] ? 'img' : 'chat', //为chat或img//消息类型
                    'agentId': config.agentid || that.selfData.uid,
                    'agentname': that.selfData.showname,
                    'msgMine': true,
                    'time': getMsgTime(date),
                    'id': date.getTime(),
                    'autoMsg': autoMsg || 0,
                    'houseid': selectContact.houseid || '', // 新增 houseid 字段
                    'ShopID': selectContact.ShopID || selectContact.shopid || '',
                    'ShopType': selectContact.ShopType || selectContact.shoptype || '',
                    'projinfo': selectContact.projinfo || ''
                };
                that.setPicData('');
                //2015.4.21 屏蔽下writeMsg，只是发消息，不写入到消息列表，flash在sendmsg时会调用js的receiveMsg方法将消息输出
                //2015.4.23 不屏蔽writeMsg，先写入并显示，传flash的发消息和通知其他client, 不通知自己
                //autoMsg == 1 给经纪人发送的一句话，只发送不显示
                //autoMsg == 2 自动回复，只显示不发送

                if (autoMsg !== 1) {
                    that.writeMsg(msgData);
                    event.trigger("model:msg:save", msgData.sendto);
                    if (msgData.sendto == that.uiData.selectedContactId) {
                        event.trigger('model:msg:change', msgData);
                        if (that.uiData.selectedContactId != that.contactsDataList[0].contactId) {
                            insertHead(that.uiData.selectedContactId, that.contactsDataList);
                            event.trigger("model:contacts:change", that.contactsDataList);
                            var selectContactData = getSelectedContact(that.uiData.selectedContactId, that.contactsDataList);
                            that.socket.setContactListData(that.contactsDataList);
                            event.trigger("model:singlecontact:change", selectContactData);
                        }
                    }
                }
                // 传给flash
                that.socket.sendMsg(msgData);
                return true;
            },
            /**
             * 设置新消息显示
             */
            setNewMsgShow: function () {
                var selectedContact = this.getHasNewMsgContact();
                if (selectedContact) {
                    this.setBoxStateAndSelectedContactId(setting.WINDOW_STATUS_MAX, selectedContact.contactId);
                }
            },
            /**
             * 获取有新消息得联系人
             * @returns {*}
             */
            getHasNewMsgContact: function () {
                var that = this;
                var l = that.contactsDataList.length;
                for (var i = 0; i < l; i++) {
                    if (that.contactsDataList[i].newmsgnum != 0) {
                        return that.contactsDataList[i];
                    }
                }
                return null;
            },
            /**
             * 获取历史
             */
            getHistory: function () {
                //通过socket获取历史数据可能需要传入数据直接在model里面拼接
                //this.socket.getHistory();
            },
            /**
             * 设置窗口状态
             * @param boxState 窗口状态值
             */
            setBoxState: function (boxState) {
                if (!boxState) return;
                if (boxState != setting.WINDOW_STATUS_MAX) {
                    this.uiData.selectedContactId = "";
                }
                this.setBoxStateAndSelectedContactId(boxState, this.uiData.selectedContactId);
            },
            /**
             * 设置窗口状态和当前选择的联系人id
             * @param boxState
             * @param selectedContactId
             */
            setBoxStateAndSelectedContactId: function(boxState, selectedContactId, stateObj) {
                // 判断 ui 状态和选择联系人的合理性
                if ((boxState != setting.WINDOW_STATUS_MAX && selectedContactId == '') ||
                    (boxState == setting.WINDOW_STATUS_MAX && selectedContactId)) {
                    var that = this,
                        setUI = false;
                    if (that.uiData.boxState != boxState) {
                        setUI = true;
                        that.uiData.boxState = boxState;
                        event.trigger('model:window:change', that.uiData);
                    }
                    if (that.uiData.selectedContactId != selectedContactId) {
                        setUI = true;
                        var contactChange = false;
                        that.uiData.selectedContactId = selectedContactId;
                        var selectContactData = getSelectedContact(that.uiData.selectedContactId, that.contactsDataList);
                        if (selectContactData.newmsgnum > 0) {
                            that.newMsgNum -= selectContactData.newmsgnum;
                            selectContactData.newmsgnum = 0;
                            event.trigger('model:contact:newMsg', {
                                contactData: selectContactData,
                                totalMsg: that.newMsgNum
                            });
                            contactChange = true;
                        }
                        if (stateObj && selectContactData.state !== stateObj[selectContactData.contactId]) {
                            selectContactData.state = stateObj[selectContactData.contactId];
                            contactChange = true;
                        }
                        event.trigger('model:singlecontact:change', selectContactData);
                        var msgData = that.getSelectedContactMsg();
                        event.trigger('model:msg:change', msgData);
                        // yf: 模拟收到消息自动回复，进行提示语
                        that.sendWelcome(selectContactData);
                        //如果上传过图片，则显示
                        event.trigger('model:image:change', that.picData[that.uiData.selectedContactId]);
                    }
                    if (setUI) {
                        that.socket && that.socket.setUiData(that.uiData);
                    }
                    if (contactChange) {
                        that.socket.setContactListData(that.contactsDataList);
                    }
                }
            },
            /**
             * 通过id获取当前选择的联系人的消息数据
             * @param {Object} id 当前选择的联系人id
             * @param {Object} arr 消息数据列表
             */
            getSelectedContactMsg: function() {
                var that = this;
                var arr = that.msgDataList;
                var id = that.uiData.selectedContactId;
                if (arr.hasOwnProperty(id)) {
                    return arr[id];
                }
                return [];
            },
            getSelectedContactHistoryMsg: function(contactId) {
                var that = this;
                if (undefined === contactId) {
                    contactId = that.uiData.selectedContactId;
                }
                var id = FANG_IM_MSG_DATA_LIST + contactId;
                var msgData;
                if (localStorage) {
                    try {
                        msgData = localStorage.getItem(id);
                        while (typeof msgData == "string") {
                            msgData = JSON.parse(msgData)
                        }
                    } catch (e) {
                        util.trace("localStorage error");
                    }

                }
                return msgData || [];
            },
            /**
             * 存储上传但未发送的图片，发送后需要清除
             * @param data
             */
            setPicData: function(data) {
                var that = this;
                that.picData[that.uiData.selectedContactId] = data || undefined;
            },
            /**
             * 设置当前活动窗口
             * @param data
             */
            setPageActive: function(data) {
                var that = this;
                if (that.socket != null) {
                    that.socket.setPageActive(data);
                }
            },
            /**
             * 接收来自通信层的聊天消息并做处理
             * @param data
             * 数据格式为
             * {autoMsg: 0
             * caller: "客户h-171656760"
             * content: "收到了你的CCCCC"
             * customerId: "fl:jinshengB"
             * id: "322969997"
             * msgForeign: 1
             * msgRelate: {account: "jinshengB"city: "上海"}
             * msgState: 0
             * msgType: 0
             * time: 1429322915892
             * userType: "webhomeclient"
             * userid: "80623d8eca243571"
             * }
             */
            receiveMsg: function(data) {
                var that = this;
                var msgData = that.formatMsgData(data);
                var msgDataList = that.msgDataList[msgData.caller];
                if (undefined != msgDataList && that.sameMsgData(msgData, msgDataList[msgDataList.length - 1])) return;
                var contactData = that.getContactDataById(msgData.caller);
                if (!contactData) {
                    //如果联系人不存在，则需要添加联系人
                    contactData = that.writeContactData({
                        'contactId': msgData.caller,
                        'showname': msgData.caller
                    });
                    event.trigger('model:contacts:change', that.contactsDataList);
                    event.trigger('model:contacts:numChange', that.contactsOnlineStatus);
                }
                msgData.agentname = contactData.showname;
                that.writeMsg(msgData);
                // event.trigger('model:msg:receive', contactData);
                event.trigger('model:msg:save', msgData.caller);
                if (msgData.caller == that.uiData.selectedContactId || msgData.caller == msgData.sendto) {
                    //如果是当前窗口，或者是自己的消息，则只显示，不统计数量
                    event.trigger('model:msg:change', msgData);
                } else {
                    contactData.newmsgnum = contactData.newmsgnum || 0;
                    contactData.newmsgnum++;
                    that.newMsgNum++;
                    event.trigger('model:contact:newMsg', {
                        contactData: contactData,
                        totalMsg: that.newMsgNum
                    });
                    that.socket.setContactListData(that.contactsDataList);
                }
                if (contactData) {
                    event.trigger('model:singleContact:state', contactData);
                }
            },
            /**
             * 格式化消息数据
             * @param data
             * @returns {{form: *, sendto: (fetchParam.userid|*|.data.userid), content: (*|string|CSSStyleDeclaration.content|content), command: string, agentId: *, agentname: (*|Function), msgMine: boolean, caller: (*|Function), time: (*|time)}}
             * msgType 消息类型标识
             * 0 chat 普通消息
             * 0 chat 案例 purpose：anli
             * 1 img 图片
             * 2 com_card 通用卡片（房源卡片）
             *     content: B端传值为json字符串形式
             *         purpose：集团_电商（非电商，其他）_业务类型,
             *         title1,title2,desc1,desc2,tap1,tap2,
             *         img：图片链接,
             *         wapurl：跳转链接,
             *         fromtype:来源
             * 3 red_packets_cash, red_packets_cash_ret 现金红包
             * 4 newhouses 房天下红包（楼盘红包） purpose：xfb_soufun_redbag
             * 4 newhouses 楼盘 purpose：xfb_house
             * 4 newhouses 户型 purpose：xfb_huxing
             * 5 house 房源
             * 6 voice 语音
             * 7 video 视频
             * 8 namecard 个人名片
             *     content: B端传值为json字符串形式
             *         photourl：头像,
             *         nameline：姓名,
             *         description1, description2,
             *         rightuptip： 右上角标识
             */
            formatMsgData: function(data) {
                var that = this;
                var msgType = [
                    'chat',
                    'img',
                    'com_card',
                    'red_packets_cash',
                    'newhouses',
                    'house',
                    'voice',
                    'video',
                    'namecard',
                    'location',
                    'forbidden'
                ][data.msgType];
                var msgData = {
                    form: data.customerId, //来自谁
                    sendto: data.userid, //发给谁
                    content: data.content, //消息内容
                    command: msgType, //为chat或img或com_card//消息类型
                    purpose: data.msgPurpose, // command 附加消息类型
                    agentId: data.agentId,
                    agentname: data.agentname || data.caller,
                    msgMine: !!data.msgMine,
                    caller: data.caller,
                    time: data.time || getMsgTime(new Date())
                };
                if (!msgData.msgMine) {
                    var contactData = that.getContactDataById(msgData.caller);
                    if (!contactData) {
                        contactData = formatContactData({
                            contactId: msgData.caller,
                            showname: msgData.agentname
                        });
                        that.changeContacts(contactData);
                    }
                    msgData.agentname = contactData.showname;
                }
                return msgData;
            },
            /**
             * 判断是否为同一条消息，yf: 如果不为同一条消息说明是客服发送的消息
             * @param d1 收到的消息
             * @param d2 消息列表最后一条
             * @returns {boolean}
             */
            sameMsgData: function(d1, d2) {
                return d1.time === d2.time && d1.content == d2.content; // && d1.form == d2.form && d1.sendto == d2.sendto
            },
            /**
             * 格式化消息数据列表
             * @param data
             * @returns {Array}
             */
            formatMsgDataList: function(data) {
                var that = this;
                var result = [],
                    i, len;
                if ($.isArray(data)) {
                    len = data.length;
                    for (i = 0; i < len; i++) {
                        result.push(that.formatMsgData(data[i]));
                    }
                } else {
                    result.push(that.formatMsgData(data));
                }
                return result;
            },
            /**
             * 根据contactId查找联系人
             * @param contactId
             * @returns {*}
             */
            getContactDataById: function(contactId) {
                var that = this;
                var idx = getArrIdx({
                    "contactId": contactId
                }, that.contactsDataList, that.PARM);
                return that.contactsDataList[idx];
            },
            /**
             * 用于批量更新联系人列表，适用场景：
             * 当主client联系人列表发生变化时，通知从client更新列表
             * @param data 为
             * {'fl:jinshengA': {0: {
             * autoMsg: 0
             * caller: "fl:jinshengA"
             * content: "cccccccccccccccccccccc"
             * customerId: "e12bc20bda7744b9"
             * id: "1429594807309"
             * msgMine: 0
             * msgType: 0
             * time: 1429594807309
             * userType: "flash"
             * userid: "fl:jinshengA"
             * }
             * fixed: false,
             * length: 1
             *}}
             */
            msgDataChange: function(data) {
                var that = this;
                //格式转化，便于比较
                var obj = {},
                    key, i = 0,
                    len, d, d1, d2, l1, l2, start;
                var hasNewMsg = false;
                for (key in data) {
                    d = $.makeArray(data[key]);
                    obj[key] = d;
                }
                //obj为传回来的消息列表,mdata为本地消息列表
                //与本地存的数据对比，如果有变化则更新视图，否则不更新
                var mdata = that.msgDataList;
                for (key in obj) {
                    hasNewMsg = false;
                    if (!mdata[key] || mdata[key].length < 1) {
                        if (!!obj[key] && obj[key].length > 0) {
                            mdata[key] = that.formatMsgDataList(obj[key]);
                            hasNewMsg = true;
                        }
                    } else {
                        if (!obj[key]) break;
                        /*l1 = mdata[key].length;
                         l2 = obj[key].length;
                         d1 = mdata[key][l1 - 1];
                         //倒序遍历obj找到相同
                         for (i = l2 - 1; i >= 0; i--) {
                         d2 = obj[key][i];
                         if (d1.time === d2.time) {//d1.caller === d2.caller &&
                         break;
                         }
                         }
                         if (i+1 < l2 - 1) {
                         //最后一个一致，什么也不做 DO NOTHING
                         //如果不是最后，则把obj中i之后的数据添加到mdata
                         start = i + 1;
                         for (i = start; i < l2; i++) {
                         var msgData = that.formatMsgData(obj[key][i]);
                         mdata[key].push(msgData);
                         }
                         hasNewMsg = true;
                         }*/
                        /*由于上述方法有可能出现比较了最后一个相同，但是实际长度会不同的情况出现*/
                        l1 = mdata[key].length;
                        l2 = obj[key].length;
                        if (obj[key].length != mdata[key].length) {
                            mdata[key].splice(0, l1);
                            for (i = 0; i < l2; i++) {
                                mdata[key][i] = that.formatMsgData(obj[key][i]);
                            }
                            hasNewMsg = true;
                            //清除自动回复
                            //event.trigger('model:msg:receive', key);
                            event.trigger('model:msg:save', key);
                        }
                    }
                    if (hasNewMsg === true && key == that.uiData.selectedContactId) {
                        event.trigger('model:msg:change', mdata[that.uiData.selectedContactId]);
                    }
                }
            },
            mergeMsgData: function(msgDataHis, msgData, exports) {
                var that = this;
                //格式转化，便于比较
                var obj = msgData,
                    i = 0,
                    len, d, d1, d2, l1, l2, start;
                var hasNewMsg = false;
                //obj为传回来的消息列表, msgDataHis为本地存储消息列表
                //与本地存的数据对比，如果有变化则更新视图，否则不更新
                if (!obj || obj.length < 1) {
                    hasNewMsg = false
                } else if (!msgDataHis || msgDataHis.length < 1) {
                    if (!!obj && obj.length > 0) {
                        msgDataHis = obj;
                        hasNewMsg = true;
                    }
                } else {
                    l1 = msgDataHis.length;
                    l2 = obj.length;
                    d1 = msgDataHis[l1 - 1];
                    //倒序遍历obj找到相同
                    for (i = l2 - 1; i >= 0; i--) {
                        d2 = obj[i];
                        if (d1.time == d2.time && d1.content == d2.content) {
                            break;
                        }
                    }
                    if (i + 1 <= l2 - 1) {
                        //最后一个一致，什么也不做 DO NOTHING
                        //如果不是最后，则把obj中i之后的数据添加到msgDataHis
                        start = i + 1;
                        for (i = start; i < l2; i++) {
                            msgDataHis.push(obj[i]);
                        }
                        hasNewMsg = true;
                    }
                }
                exports.data = msgDataHis;
                return hasNewMsg;
            },
            /**
             * 设置为主窗口
             * @param data
             */
            setMaster: function(data) {
                util.trace('Info::modelParse.setMaster', data);
                if (this.isMaster != data) {
                    this.isMaster = data;
                    //主client 轮询联系人在线状态
                    event.trigger("model:contacts:pollingState");
                }
            },
            /**
             * 设置离线自动回复 原setAutoReplay 方法
             * @param contactId 客服或顾问 ID
             * @param data 自动回复内容
             */
            sendReplyMessage: function (contactId, data, onlyWrite) {
                var that = this;
                if (!data) {
                    util.trace('Wrong::modelParse.sendAutoReplay--不能发送空数据');
                    return;
                }
                if (!contactId) {
                    util.trace('Wrong::modelParse.sendAutoReplay--请选择发送对象');
                    return;
                }
                var contactData = that.getContactDataById(contactId);
                var date = new Date();
                var msgData = {
                    'form': contactId, //来自谁
                    'caller': contactId,
                    'sendto': that.selfData.uid, //发给谁
                    'content': data, //消息内容
                    'command': 'chat', //为chat或img//消息类型
                    'agentId': contactData.contactId,
                    'agentname': contactData.showname,
                    'msgMine': false,
                    'time': getMsgTime(date),
                    'id': date.getTime(),
                    'autoMsg': 2,
                    'houseid': contactData.houseid || '', // 新增 houseid 字段
                    'ShopID': contactData.ShopID || contactData.shopid || '',
                    'ShopType': contactData.ShopType || contactData.shoptype || '',
                    'projinfo': contactData.projinfo || ''
                };
                // autoMsg == 2 自动回复，只显示不发送 给 flash
                if (onlyWrite) {
                    that.writeMsg(msgData);
                    event.trigger('model:msg:save', msgData.sendto);
                    if (contactId === that.uiData.selectedContactId) {
                        event.trigger('model:msg:change', msgData);
                    }
                } else {
                    // 传给flash
                    that.socket.sendMsg(msgData);
                }
                return true;
            },
            /**
             * 设置离线自动回复
             * @param contactId
             * @param setReply
             */
            delayAutoReply: function (contactId, delaySecond) {
                var that = this;
                clearTimeout(autoReplyTimerList[contactId]);

                if (config.type !== setting.type.jiaju) {
                    autoReplyTimerList[contactId] = setTimeout(function () {
                        var replyText = defaultReplyConfig.default;
                        if (config.type === setting.type.zxb) {
                            replyText = defaultReplyConfig.custom.noUser;
                        }
                        that.sendReplyMessage(contactId, replyText, true);
                        clearTimeout(autoReplyTimerList[contactId]);
                    }, delaySecond);
                    return;
                }
                if (config.type === setting.type.jiaju) {
                    autoReplyTimerList[contactId] = setTimeout(function () {
                        //encodeURIComponent(escape('波涛精品设计'))=> "%25u6CE2%25u6D9B%25u7CBE%25u54C1%25u8BBE%25u8BA1"
                        var temp, obj;
                        if (jiajuReplyTextList[contactId]) {
                            that.sendReplyMessage(contactId, jiajuReplyTextList[contactId]);
                            clearTimeout(autoReplyTimerList[contactId]);
                        } else {
                            temp = contactId.split(':');
                            obj = {
                                'username': escape(temp[1] || temp[0])
                            };
                            $.ajax({
                                url: setting.JIAJU_AUTO_REPLY_PATH,
                                data: obj,
                                cache: true,
                                dataType: 'jsonp', //类型
                                timeout: setting.POLLING_INTERVAL,
                                jsonp: 'callback', //jsonp回调参数，必需
                                success: function (data) {
                                    jiajuReplyTextList[contactId] = decodeURIComponent(data);
                                    that.sendReplyMessage(contactId, jiajuReplyTextList[contactId]);
                                    clearTimeout(autoReplyTimerList[contactId]);
                                }
                            });
                        }
                    }, delaySecond);
                }
            },
            setNoUserReply: function (type) {
                var contactId = this.uiData.selectedContactId;

                if (type === 'receive') {
                    // 搜房帮去掉自动回复，20170706
                    if (config.type === setting.type.zxb) {
                        this.delayAutoReply(contactId, defaultReplyConfig.custom.delay);
                        return;
                    }
                }

                if (type === 'send') {
                    // 搜房帮去掉自动回复，20170706
                    if (config.type === setting.type.zxb) {
                        clearTimeout(autoReplyTimerList[contactId]);
                        return;
                    }
                    var contact = this.getContactDataById(contactId);
                    // 家居没有欢迎语，直接进行计时自动回复
                    var prefix = contactId.split(':')[0];
                    if ((prefix === 'h' || prefix === 'j') && contact.type === setting.type.jiaju) {
                        if (contact.state === 1) {
                            // 家居定时30秒后显示自动回复
                            this.delayAutoReply(contactId, 30 * 1000);
                        }
                    }
                    // fs 表示海外客服前缀 yf: 搜房帮也是 fs 前缀
                    if (prefix === 'fs' && contact.type === setting.type.haiwai) {
                        // 海外定时2分钟
                        if (contact.state === 1) {
                            this.delayAutoReply(contactId, 60 * 1000); // 60 * 1000
                        }
                    }
                }
            },
            // yf: 从setBoxStateAndSelectedContactId 提取功能，问候语提示 sessionStorage 不在线:在线
            sendWelcome: function (contact) {
                // 搜房帮特殊处理，要在点击客服时提示一条信息
                var contactId = contact.contactId,
                    state = contact.state;

                var greetId = 'greet_' + contactId;
                if (config.type === setting.type.sfb || config.type === setting.type.zxb) {
                    var msg = '';
                    var greetSession = sessionStorage.getItem(greetId);
                    var flag = (greetSession || '0;0').split(';');
                    // 如果在线，没有发送过欢迎语
                    if (flag[1] !== '1' && state === 1) {
                        msg = defaultReplyConfig.custom.online;
                        sessionStorage.setItem(greetId, flag[0] + ';1');
                    }
                    // 如果不在线，没有发送过欢迎语
                    if (flag[0] !== '1' && state === 0) {
                        msg = defaultReplyConfig.custom.offline;
                        sessionStorage.setItem(greetId, '1;' + flag[1]);
                    }
                    // 发送欢迎语
                    if (msg) {
                        this.sendReplyMessage(contactId, msg, true);
                        // yf：发送消息或切换客服需要重新监听倒计时，发送结束语。
                    }
                    if (state === 1) {
                        this.setNoUserReply('receive');
                    }
                    return;
                }

                // 海外im特殊处理，要在点击客服时提示一条信息。yf: 什么时候使用 config.type 什么时候使用 contact.type
                if (contact.type === setting.type.haiwai) {
                    if (!sessionStorage.getItem(greetId)) {
                        this.sendReplyMessage(contactId, '亲爱的用户，这里是房天下海外房产，请问有什么需要帮助？', true);
                        sessionStorage.setItem(greetId, '1;1');
                    }
                    return;
                }

                // 2.0.6 新增 xf, esf, zf 提示语不发送。
                // 为什么没有用 contact.type 和 setting.type 判断？因为比如新房页面 init => type:'webxf' 但经纪人 add => type:'xf'
                if (config.type === setting.type.xf || config.type === setting.type.esf || config.type === setting.type.zf) {
                    if (!sessionStorage.getItem(greetId)) {
                        var text = '您好！我是经纪人' + contact.showname + '，请问有什么可以帮助您？';
                        if (config.type === setting.type.xf) {
                            text = '您好！我是置业顾问' + contact.showname + '，请问有什么可以帮助您？';
                        };
                        this.sendReplyMessage(contactId, text, true);
                        sessionStorage.setItem(greetId, '1;1');
                    }
                }
            },
        };
        var instance;
        var _static = {
            name: 'modelParse',
            getInstance: function(args) {
                if (instance === undefined) {
                    instance = new modelParse(args);
                }
                return instance;
            }
        };
        return _static;
    })();
    module.exports = modelParseSingle;
});
